home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / language / pcl_src.zoo / walk.lsp < prev    next >
Text File  |  1992-09-09  |  79KB  |  2,273 lines

  1. ;;;-*- Mode:LISP; Package:(WALKER LISP 1000); Base:10; Syntax:Common-lisp -*-
  2. ;;;
  3. ;;; *************************************************************************
  4. ;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
  5. ;;; All rights reserved.
  6. ;;;
  7. ;;; Use and copying of this software and preparation of derivative works
  8. ;;; based upon this software are permitted.  Any distribution of this
  9. ;;; software or derivative works must comply with all applicable United
  10. ;;; States export control laws.
  11. ;;; 
  12. ;;; This software is made available AS IS, and Xerox Corporation makes no
  13. ;;; warranty about the software, its performance or its conformity to any
  14. ;;; specification.
  15. ;;; 
  16. ;;; Any person obtaining a copy of this software is requested to send their
  17. ;;; name and post office or electronic mail address to:
  18. ;;;   CommonLoops Coordinator
  19. ;;;   Xerox PARC
  20. ;;;   3333 Coyote Hill Rd.
  21. ;;;   Palo Alto, CA 94304
  22. ;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  23. ;;;
  24. ;;; Suggestions, comments and requests for improvements are also welcome.
  25. ;;; *************************************************************************
  26. ;;; 
  27. ;;; A simple code walker, based IN PART on: (roll the credits)
  28. ;;;   Larry Masinter's Masterscope
  29. ;;;   Moon's Common Lisp code walker
  30. ;;;   Gary Drescher's code walker
  31. ;;;   Larry Masinter's simple code walker
  32. ;;;   .
  33. ;;;   .
  34. ;;;   boy, thats fair (I hope).
  35. ;;;
  36. ;;; For now at least, this code walker really only does what PCL needs it to
  37. ;;; do.  Maybe it will grow up someday.
  38. ;;;
  39.  
  40. ;;;
  41. ;;; This code walker used to be completely portable.  Now it is just "Real
  42. ;;; easy to port".  This change had to happen because the hack that made it
  43. ;;; completely portable kept breaking in different releases of different
  44. ;;; Common Lisps, and in addition it never worked entirely anyways.  So,
  45. ;;; its now easy to port.  To port this walker, all you have to write is one
  46. ;;; simple macro and two simple functions.  These macros and functions are
  47. ;;; used by the walker to manipluate the macroexpansion environments of
  48. ;;; the Common Lisp it is running in.
  49. ;;;
  50. ;;; The code which implements the macroexpansion environment manipulation
  51. ;;; mechanisms is in the first part of the file, the real walker follows it.
  52. ;;; 
  53.  
  54. (in-package 'walker)
  55.  
  56. ;;;
  57. ;;; The user entry points are walk-form and nested-walked-form.  In addition,
  58. ;;; it is legal for user code to call the variable information functions:
  59. ;;; variable-lexical-p, variable-special-p and variable-class.  Some users
  60. ;;; will need to call define-walker-template, they will have to figure that
  61. ;;; out for themselves.
  62. ;;; 
  63. (export '(define-walker-template
  64.       walk-form
  65.       nested-walk-form
  66.       variable-lexical-p
  67.       variable-special-p
  68.       variable-globally-special-p
  69.       *variable-declarations*
  70.       variable-declaration
  71.       ))
  72.  
  73.  
  74.  
  75. ;;;
  76. ;;; On the following pages are implementations of the implementation specific
  77. ;;; environment hacking functions for each of the implementations this walker
  78. ;;; has been ported to.  If you add a new one, so this walker can run in a new
  79. ;;; implementation of Common Lisp, please send the changes back to us so that
  80. ;;; others can also use this walker in that implementation of Common Lisp.
  81. ;;;
  82. ;;; This code just hacks 'macroexpansion environments'.  That is, it is only
  83. ;;; concerned with the function binding of symbols in the environment.  The
  84. ;;; walker needs to be able to tell if the symbol names a lexical macro or
  85. ;;; function, and it needs to be able to build environments which contain
  86. ;;; lexical macro or function bindings.  It must be able, when walking a
  87. ;;; macrolet, flet or labels form to construct an environment which reflects
  88. ;;; the bindings created by that form.  Note that the environment created
  89. ;;; does NOT have to be sufficient to evaluate the body, merely to walk its
  90. ;;; body.  This means that definitions do not have to be supplied for lexical
  91. ;;; functions, only the fact that that function is bound is important.  For
  92. ;;; macros, the macroexpansion function must be supplied.
  93. ;;;
  94. ;;; This code is organized in a way that lets it work in implementations that
  95. ;;; stack cons their environments.  That is reflected in the fact that the
  96. ;;; only operation that lets a user build a new environment is a with-body
  97. ;;; macro which executes its body with the specified symbol bound to the new
  98. ;;; environment.  No code in this walker or in PCL will hold a pointer to
  99. ;;; these environments after the body returns.  Other user code is free to do
  100. ;;; so in implementations where it works, but that code is not considered
  101. ;;; portable.
  102. ;;;
  103. ;;; There are 3 environment hacking tools.  One macro which is used for
  104. ;;; creating new environments, and two functions which are used to access the
  105. ;;; bindings of existing environments.
  106. ;;;
  107. ;;; WITH-AUGMENTED-ENVIRONMENT
  108. ;;;
  109. ;;; ENVIRONMENT-FUNCTION
  110. ;;;
  111. ;;; ENVIRONMENT-MACRO
  112. ;;; 
  113.  
  114. (defun unbound-lexical-function (&rest args)
  115.   (declare (ignore args))
  116.   (error "The evaluator was called to evaluate a form in a macroexpansion~%~
  117.           environment constructed by the PCL portable code walker.  These~%~
  118.           environments are only useful for macroexpansion, they cannot be~%~
  119.           used for evaluation.~%~
  120.           This error should never occur when using PCL.~%~
  121.           This most likely source of this error is a program which tries to~%~
  122.           to use the PCL portable code walker to build its own evaluator."))
  123.  
  124.  
  125. ;;;
  126. ;;; In Coral Common Lisp, the macroexpansion environment is just a list
  127. ;;; of environment entries.  The cadr of each element specifies the type
  128. ;;; of the element.  The only types that interest us are CCL::MACRO and
  129. ;;; FUNCTION.  In these cases the element is interpreted as follows.
  130. ;;;
  131. ;;;   (<function-name> CCL::MACRO . macroexpansion-function)
  132. ;;;   
  133. ;;;   (<function-name> FUNCTION . <fn>)
  134. ;;;   
  135. ;;;   When in the compiler, <fn> is a gensym which will be
  136. ;;;   a variable which bound at run-time to the function.
  137. ;;;   When in the interpreter, <fn> is the actual function.
  138. ;;;   
  139. ;;;
  140. #+:Coral
  141. (progn 
  142.   #-:cltl2
  143.   (progn
  144.     
  145.     (defmacro with-augmented-environment
  146.           ((new-env old-env &key functions macros) &body body)
  147.       `(let ((,new-env (with-augmented-environment-internal ,old-env
  148.                          ,functions
  149.                          ,macros)))
  150.          ,@body))
  151.     
  152.     (defun with-augmented-environment-internal (env functions macros)
  153.       (dolist (f functions)
  154.         (push (list* f 'function (gensym)) env))
  155.       (dolist (m macros)
  156.         (push (list* (car m) 'ccl::macro (cadr m)) env))
  157.       env)
  158.     
  159.     (defun environment-function (env fn)
  160.       (let ((entry (assoc fn env :test #'equal)))
  161.         (and entry
  162.          (eq (cadr entry) 'function)
  163.          (cddr entry))))
  164.     
  165.     (defun environment-macro (env macro)
  166.       (let ((entry (assoc macro env :test #'equal)))
  167.         (and entry
  168.          (eq (cadr entry) 'ccl::macro)
  169.          (cddr entry))))
  170.     
  171.     )
  172.   #+:cltl2                              ; This isn't Coral specific
  173.      (defmacro with-augmented-environment
  174.           ((new-env old-env &key functions macros) &body body)
  175.       `(let ((,new-env (with-augmented-environment-internal ,old-env
  176.                          ,functions
  177.                          ,macros)))
  178.          ,@body))
  179.                                        ; Should work in any ClTl2 implimentation
  180.   #+cltl2(progn
  181.     (defun with-augmented-environment-internal (env functions macros)
  182.       (let ((functions-and-defs
  183.              (mapcar #'(lambda (f)
  184.                          (car f) ) functions))
  185.             (macros-and-defs
  186.              (mapcar #'(lambda (m)
  187.                          (list (car m) (cadr m))) macros)))
  188.         (cl:augment-environment env
  189.                                 :function functions-and-defs :macro macros-and-defs)
  190.         )
  191.       )
  192.     
  193.     (defun environment-function (env fn)
  194.       (multiple-value-bind (type )
  195.                            (cl:function-information fn env)
  196.         (eql type :function)))
  197.     
  198.     (defun environment-macro (env fn)
  199.       (multiple-value-bind (type )
  200.                            (cl:function-information fn env)
  201.         (if (eql type :macro)
  202.           (macro-function fn env ))))
  203.     
  204.     ));#+:Coral
  205.  
  206.  
  207. ;;;
  208. ;;; Franz Common Lisp is a lot like Coral Lisp.  The macroexpansion
  209. ;;; environment is just a list of entries.  The cadr of each element
  210. ;;; specifies the type of the element.  The types that interest us
  211. ;;; are FUNCTION, EXCL::MACRO, and COMPILER::FUNCTION-VALUE.  These
  212. ;;; are interpreted as follows:
  213. ;;;
  214. ;;;   (<function-name> FUNCTION . <a lexical closure>)
  215. ;;;
  216. ;;;      This happens in the interpreter with lexically
  217. ;;;      bound functions.
  218. ;;;
  219. ;;;   (<function-name> COMPILER::FUNCTION-VALUE . <gensym>)
  220. ;;;
  221. ;;;      This happens in the compiler.  The gensym represents
  222. ;;;      a variable which will be bound at run time to the
  223. ;;;      function object.
  224. ;;;
  225. ;;;   (<function-name> EXCL::MACRO . <a lambda>)
  226. ;;;
  227. ;;;      In both interpreter and compiler, this is the
  228. ;;;      representation used for macro definitions.
  229. ;;;   
  230. ;;;
  231. #+:ExCL
  232. (progn
  233.  
  234. (defmacro with-augmented-environment
  235.       ((new-env old-env &key functions macros) &body body)
  236.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  237.                             ,functions
  238.                             ,macros)))
  239.      ,@body))
  240.  
  241. (defun with-augmented-environment-internal (env functions macros)
  242.   (dolist (f functions)
  243.     (push (list* f 'function #'unbound-lexical-function) env))
  244.   (dolist (m macros)
  245.     (push (list* (car m) 'excl::macro (cadr m)) env))
  246.   env)
  247.  
  248. (defun environment-function (env fn)
  249.   (let ((entry (assoc fn env :test #'equal)))
  250.     (and entry
  251.      (or (eq (cadr entry) 'function)
  252.          (eq (cadr entry) 'compiler::function-value))
  253.      (cddr entry))))
  254.  
  255. (defun environment-macro (env macro)
  256.   (let ((entry (assoc macro env :test #'equal)))
  257.     (and entry
  258.      (eq (cadr entry) 'excl::macro)
  259.      (cddr entry))))
  260.  
  261. );#+:ExCL
  262.  
  263.  
  264. #+Lucid
  265. (progn
  266.   
  267. (proclaim '(inline
  268.         %alphalex-p
  269.         add-contour-to-env-shape
  270.         make-function-variable
  271.         make-sfc-contour
  272.         sfc-contour-type
  273.         sfc-contour-elements
  274.         add-sfc-contour
  275.         add-function-contour
  276.         add-macrolet-contour
  277.         find-variable-in-contour
  278.         find-alist-element-in-contour
  279.         find-macrolet-in-contour))
  280.  
  281. (defun %alphalex-p (object)
  282.   #-Prime
  283.   (eq (cadddr (cddddr object)) 'lucid::%alphalex)
  284.   #+Prime
  285.   (eq (caddr (cddddr object)) 'lucid::%alphalex))
  286.  
  287. #+Prime 
  288. (defun lucid::augment-lexenv-fvars-dummy (lexical vars)
  289.   (lucid::augment-lexenv-fvars-aux lexical vars '() '() 'flet '()))
  290.  
  291. (defconstant function-contour 1)
  292. (defconstant macrolet-contour 5)
  293.  
  294. (defstruct lucid::contour
  295.   type
  296.   elements)
  297.  
  298. (defun add-contour-to-env-shape (contour-type elements env-shape)
  299.   (cons (make-contour :type contour-type
  300.               :elements elements)
  301.     env-shape))
  302.  
  303. (defstruct (variable (:constructor make-variable (name source-type)))
  304.   name
  305.   (identifier nil)
  306.   source-type)
  307.  
  308. (defconstant function-sfc-contour 1)
  309. (defconstant macrolet-sfc-contour 8)
  310. (defconstant function-variable-type 1)
  311.  
  312. (defun make-function-variable (name)
  313.   (make-variable name function-variable-type))
  314.  
  315. (defun make-sfc-contour (type elements)
  316.   (cons type elements))
  317.  
  318. (defun sfc-contour-type (sfc-contour)
  319.   (car sfc-contour))
  320.  
  321. (defun sfc-contour-elements (sfc-contour)
  322.   (cdr sfc-contour))
  323.  
  324. (defun add-sfc-contour (element-list environment type)
  325.   (cons (make-sfc-contour type element-list) environment))
  326.  
  327. (defun add-function-contour (variable-list environment)
  328.   (add-sfc-contour variable-list environment function-sfc-contour))
  329.  
  330. (defun add-macrolet-contour (alist environment)
  331.   (add-sfc-contour alist environment macrolet-sfc-contour))
  332.  
  333. (defun find-variable-in-contour (name contour)
  334.   (dolist (element (sfc-contour-elements contour) nil)
  335.     (when (eq (variable-name element) name)
  336.       (return element))))
  337.  
  338. (defun find-alist-element-in-contour (name contour)
  339.   (cdr (assoc name (sfc-contour-elements contour))))
  340.  
  341. (defun find-macrolet-in-contour (name contour)
  342.   (find-alist-element-in-contour name contour))
  343.  
  344. (defmacro do-sfc-contours ((contour-var environment &optional result)
  345.                &body body)
  346.   `(dolist (,contour-var ,environment ,result) ,@body))
  347.  
  348.  
  349. (defmacro with-augmented-environment
  350.       ((new-env old-env &key functions macros) &body body)     
  351.   `(let* ((,new-env (with-augmented-environment-internal ,old-env
  352.                              ,functions
  353.                              ,macros)))
  354.      ,@body))
  355.  
  356. ;;;
  357. ;;; with-augmented-environment-internal is where the real work of augmenting
  358. ;;; the environment happens.
  359. ;;; 
  360. (defun with-augmented-environment-internal (env functions macros)
  361.   (let ((function-names (mapcar #'first functions))
  362.     (macro-names (mapcar #'first macros))
  363.     (macro-functions (mapcar #'second macros)))
  364.     (cond ((or (null env)
  365.            (contour-p (first env)))
  366.        (when function-names
  367.          (setq env (add-contour-to-env-shape function-contour
  368.                          function-names
  369.                          env)))
  370.        (when macro-names
  371.          (setq env (add-contour-to-env-shape macrolet-contour
  372.                          (pairlis macro-names
  373.                               macro-functions)
  374.                          env))))
  375.       ((%alphalex-p env)
  376.        (when function-names
  377.          (setq env (lucid::augment-lexenv-fvars-dummy env function-names)))
  378.        (when macro-names
  379.          (setq env (lucid::augment-lexenv-mvars env
  380.                             macro-names
  381.                             macro-functions))))
  382.       (t
  383.        (when function-names
  384.          (setq env (add-function-contour
  385.              (mapcar #'make-function-variable function-names)
  386.              env)))
  387.        (when macro-names
  388.          (setq env (add-macrolet-contour
  389.              (pairlis macro-names macro-functions)
  390.              env)))))
  391.     env))
  392.      
  393.  
  394. (defun environment-function (env fn)
  395.   (cond ((null env) nil)
  396.     ((contour-p (first env))
  397.      (if (lucid::find-lexical-function fn env)
  398.          t
  399.          nil))
  400.     ((%alphalex-p env)
  401.      (if (lucid::lexenv-fvar fn env)
  402.          t
  403.          nil))
  404.     (t (do-sfc-contours (contour env nil)
  405.          (let ((type (sfc-contour-type contour)))
  406.            (cond ((eql type function-sfc-contour)
  407.               (when (find-variable-in-contour fn contour)
  408.             (return t)))
  409.              ((eql type macrolet-sfc-contour)
  410.               (when (find-macrolet-in-contour fn contour)
  411.             (return nil)))))))))
  412.               
  413. (defun environment-macro (env macro)
  414.   (cond ((null env) nil)
  415.     ((contour-p (first env))
  416.      (lucid::find-lexical-macro macro env))
  417.     ((%alphalex-p env)
  418.      (lucid::lexenv-mvar macro env))
  419.     (t (do-sfc-contours (contour env nil)
  420.          (let ((type (sfc-contour-type contour)))
  421.            (cond ((eql type function-sfc-contour)
  422.               (when (find-variable-in-contour macro contour)
  423.             (return nil)))
  424.              ((eql type macrolet-sfc-contour)
  425.               (let ((fn (find-macrolet-in-contour macro contour)))
  426.             (when fn
  427.               (return fn))))))))))
  428.   
  429.  
  430. );#+Lucid
  431.  
  432.  
  433.  
  434. ;;;
  435. ;;; On the 3600, the documentation for how the environments are represented
  436. ;;; is in sys:sys;eval.lisp.  That total information is not repeated here.
  437. ;;; The important points are that:
  438. ;;;    si:env-variables returns a list of which each element is:
  439. ;;;
  440. ;;;        (symbol value)
  441. ;;;         or (symbol . locative)
  442. ;;;
  443. ;;;    The first form is for lexical variables, the second for
  444. ;;;    special and instance variables.  In either case CADR of
  445. ;;;    the entry is the value and SETF of CADR is used to change
  446. ;;;    the value.  Variables are looked up with ASSQ.
  447. ;;;
  448. ;;;    si:env-functions returns a list of which each element is:
  449. ;;;     
  450. ;;;        (symbol definition)
  451. ;;;
  452. ;;;    where definition is anything that could go in a function cell.
  453. ;;;    This is used for both local functions and local macros.
  454. ;;;
  455. ;;; The 3600 stack conses its environments (at least in the interpreter).
  456. ;;; This means that code written using this walker and running on the 3600
  457. ;;; must not hold on to the environment after the walk-function returns.
  458. ;;; No code in this walker or in PCL does that.
  459. ;;;
  460. #+Genera
  461. (progn
  462.  
  463. (defmacro with-augmented-environment
  464.       ((new-env old-env &key functions macros) &body body)
  465.   (let ((funs (make-symbol "FNS"))
  466.     (macs (make-symbol "MACROS"))
  467.     (new  (make-symbol "NEW")))
  468.     `(let ((,funs ,functions)
  469.        (,macs ,macros)
  470.        (,new ()))
  471.        (dolist (f ,funs)
  472.      (push `(,(car f) ,#'unbound-lexical-function) ,new))
  473.        (dolist (m ,macs)
  474.      (push `(,(car m) (special ,(cadr m))) ,new))
  475.        (let* ((.old-env. ,old-env)
  476.           (.old-vars. (pop .old-env.))
  477.           (.old-funs. (pop .old-env.))
  478.           (.old-blks. (pop .old-env.))
  479.           (.old-tags. (pop .old-env.))
  480.           (.old-dcls. (pop .old-env.)))
  481.      (si:with-interpreter-environment (,new-env
  482.                        .old-env.
  483.                        .old-vars.
  484.                        (append ,new .old-funs.)
  485.                        .old-blks.
  486.                        .old-tags.
  487.                        .old-dcls.)
  488.        ,@body)))))
  489.   
  490.  
  491. (defun environment-function (env fn)
  492.   (if (null env)
  493.       (values nil nil)
  494.       (let ((entry (assoc fn (si:env-functions env) :test #'equal)))
  495.     (if (and entry
  496.          (or (not (listp (cadr entry)))
  497.              (not (eq (caadr entry) 'special))))
  498.         (values (cadr entry) t)
  499.         (environment-function (si:env-parent env) fn)))))
  500.  
  501. (defun environment-macro (env macro)
  502.   (if (null env)
  503.       (values nil nil)
  504.       (let ((entry (assoc macro (si:env-functions env) :test #'equal)))
  505.     (if (and entry
  506.          (listp (cadr entry))
  507.          (eq (caadr entry) 'special))
  508.         (values (cadadr entry) t)
  509.         (environment-macro (si:env-parent env) macro)))))
  510.  
  511. );#+Genera
  512.  
  513. #+Cloe-Runtime
  514. (progn
  515.  
  516. (defmacro with-augmented-environment
  517.       ((new-env old-env &key functions macros) &body body)
  518.   `(let ((,new-env (with-augmented-environment-internal ,old-env ,functions ,macros)))
  519.      ,@body))
  520.  
  521. (defun with-augmented-environment-internal (env functions macros)
  522.   functions
  523.   (dolist (m macros)
  524.     (setf env `(,(first m) (compiler::macro . ,(second m)) ,@env)))
  525.   env)
  526.  
  527. (defun environment-function (env fn)
  528.   nil)
  529.  
  530. (defun environment-macro (env macro)
  531.   (let ((entry (getf env macro)))
  532.     (if (and (consp entry)
  533.          (eq (car entry) 'compiler::macro))
  534.     (values (cdr entry) t)
  535.     (values nil nil))))
  536.  
  537. );#+Cloe-Runtime
  538.  
  539.  
  540. ;;;
  541. ;;; In Xerox Lisp, the compiler and interpreter use different structures for
  542. ;;; the environment.  This doesn't cause a serious problem, the parts of the
  543. ;;; environments we are concerned with are fairly similar.
  544. ;;; 
  545. #+:Xerox
  546. (progn
  547.  
  548. (defmacro with-augmented-environment
  549.       ((new-env old-env &key functions macros) &body body)     
  550.   `(let* ((,new-env (with-augmented-environment-internal ,old-env
  551.                              ,functions
  552.                              ,macros)))
  553.      ,@body))
  554.  
  555. ;;;
  556. ;;; with-augmented-environment-internal is where the real work of augmenting
  557. ;;; the environment happens.  Before it gets there, env had better not be NIL
  558. ;;; anymore because we have to know what kind of environment we are supposed
  559. ;;; to be building up.  This is probably never a real concern in practice.
  560. ;;; It better not be because we don't do anything about it.
  561. ;;; 
  562. (defun with-augmented-environment-internal (env functions macros)
  563.   (cond
  564.      ((compiler::env-p env)
  565.     (dolist (f functions)
  566.        (setq env (compiler::copy-env-with-function
  567.                env f :function)))
  568.     (dolist (m macros)
  569.        (setq env (compiler::copy-env-with-function
  570.            env (car m) :macro (cadr m)))))
  571.      (t (setq env (if (il:environment-p env)
  572.             (il:\\copy-environment env)
  573.             (il:\\make-environment)))
  574.     ;; The functions field of the environment is a plist of function names
  575.     ;; and conses like (:function . fn) or (:macro . expansion-fn).
  576.     ;; Note that we can't smash existing entries in this plist since these
  577.     ;; are likely shared with older environments.
  578.     (dolist (f functions)
  579.       (setf (il:environment-functions env)
  580.         (list* f (cons :function #'unbound-lexical-function)
  581.                (il:environment-functions env))))
  582.     (dolist (m macros)
  583.       (setf (il:environment-functions env)
  584.         (list* (car m) (cons :macro (cadr m))
  585.                (il:environment-functions env))))))
  586.   env)
  587.  
  588. (defun environment-function (env fn)
  589.   (cond ((compiler::env-p env) (eq (compiler:env-fboundp env fn) :function))
  590.     ((il:environment-p env) (eq (getf (il:environment-functions env) fn)
  591.                     :function))
  592.     (t nil)))
  593.  
  594. (defun environment-macro (env macro) 
  595.   (cond ((compiler::env-p env)
  596.      (multiple-value-bind (type def)
  597.          (compiler:env-fboundp env macro)
  598.        (when (eq type :macro) def)))
  599.     ((il:environment-p env)
  600.      (xcl:destructuring-bind (type . def)
  601.          (getf (il:environment-functions env) macro)
  602.        (when (eq type :macro) def)))
  603.     (t nil)))
  604.  
  605. );#+:Xerox
  606.  
  607.  
  608. ;;;
  609. ;;; In IBUKI Common Lisp, the macroexpansion environment is a three element
  610. ;;; list.  The second element describes lexical functions and macros.  The 
  611. ;;; function entries in this list have the form 
  612. ;;;     (<name> . (FUNCTION . (<function-value> . nil))
  613. ;;; The macro entries have the form 
  614. ;;;     (<name> . (MACRO . (<macro-value> . nil)).
  615. ;;;
  616. ;;;
  617. #+(or KCL IBCL)
  618. (progn
  619.  
  620. (defmacro with-augmented-environment
  621.       ((new-env old-env &key functions macros) &body body)
  622.       `(let ((,new-env (with-augmented-environment-internal ,old-env
  623.                                 ,functions
  624.                                 ,macros)))
  625.          ,@body))
  626.  
  627. (defun with-augmented-environment-internal (env functions macros)
  628.   (let ((first (first env))
  629.     (lexicals (second env))
  630.     (third (third env)))
  631.     (dolist (f functions)
  632.       (push `(,(car f) .  (function  . (,#'unbound-lexical-function . nil)))
  633.         lexicals))
  634.     (dolist (m macros)
  635.       (push `(,(car m)  .  (macro . ( ,(cadr m) . nil))) 
  636.         lexicals))
  637.     (list first lexicals third)))
  638.  
  639. (defun environment-function (env fn)
  640.   (when env
  641.     (let ((entry (assoc fn (second env))))
  642.       (and entry
  643.            (eq (cadr entry) 'function)
  644.            (caddr entry)))))
  645.  
  646. (defun environment-macro (env macro)
  647.   (when env
  648.     (let ((entry (assoc macro (second env))))
  649.       (and entry
  650.            (eq (cadr entry) 'macro)
  651.            (caddr entry)))))
  652. );#+(or KCL IBCL)
  653.  
  654. ;;;
  655. ;;; In CLISP Common Lisp, the macroexpansion environment has the form
  656. ;;;   NIL  or  #(sym1 def1 ... symn defn next-env)
  657. ;;; where next-env is an macroexpansion environment of the same form.
  658. ;;; A def entry herein is a cons (SYS::MACRO . macroexpansion-function)
  659. ;;; for macros, and a symbol (a gensym in compiler, or NIL during
  660. ;;; interpretation of LABELS) or a function object for functions.
  661. ;;;
  662.  
  663. #+CLISP
  664. (progn
  665.   (defmacro with-augmented-environment
  666.             ((new-env old-env &key functions macros) &body body)
  667.     `(let ((,new-env (with-augmented-environment-internal
  668.                        ,old-env ,functions ,macros
  669.           ))         )
  670.        ,@body
  671.      )
  672.   )
  673.   (defun with-augmented-environment-internal (env functions macros)
  674.     (let* ((new-env (make-array (+ (* (+ (length functions) (length macros)) 2) 1)))
  675.            (i 0))
  676.       (dolist (f functions)
  677.         (setf (svref new-env i) f) (incf i)
  678.         (setf (svref new-env i) #'unbound-lexical-function) (incf i)
  679.       )
  680.       (dolist (m macros)
  681.         (setf (svref new-env i) (first m)) (incf i)
  682.         (setf (svref new-env i) (cons 'sys::macro (second m))) (incf i)
  683.       )
  684.       (setf (svref new-env i) env)
  685.       new-env
  686.   ) )
  687.   (defun environment-function (env fn)
  688.     (let ((h (sys::fenv-assoc fn env)))
  689.       (or (eq h 'T) ; fenv-assoc didn't find anything
  690.           (sys::closurep h) (symbolp h)
  691.   ) ) )
  692.   (defun environment-macro (env macro)
  693.     (let ((h (sys::fenv-assoc macro env)))
  694.       (if (and (consp h) (eq (car h) 'sys::macro))
  695.         (cdr h) ; macroexpansion-function
  696.         nil ; anything
  697.   ) ) )
  698. );#+CLISP
  699.  
  700.  
  701.  
  702.  
  703. ;;;   --- TI Explorer --
  704.  
  705. ;;; An environment is a two element list, whose car we can ignore and
  706. ;;; whose cadr is list of the local-definitions-frames. Each
  707. ;;; local-definitions-frame holds either macros or functions, but not
  708. ;;; both.  Each frame is a plist of <name> <def> <name> <def> ...  where
  709. ;;; <name> is a locative to the function cell of the symbol that names
  710. ;;; the function or macro, and <def> is the new def or NIL if this is function
  711. ;;; redefinition or (cons 'ticl:macro <macro-expansion-function>) if this is a macro
  712. ;;; redefinition.
  713. ;;;
  714. ;;; Here's an example.  For the form:
  715. ;;; (defun foo ()
  716. ;;;   (macrolet ((bar (a b) (list a b))
  717. ;;;             (bar2 (a b) (list a b)))
  718. ;;;     (flet ((some-local-fn (c d) (print (list c d)))
  719. ;;;           (another (c d) (print (list c d))))
  720. ;;;       (bar (some-local-fn 1 2) 3))))
  721.  
  722. ;;; the environment arg to macroexpand-1 when called on
  723. ;;; (bar (some-local-fn 1 2) 3)
  724. ;;;is 
  725. ;;;(NIL ((#<DTP-LOCATIVE 4710602> NIL
  726. ;;;       #<DTP-LOCATIVE 4710671> NIL)
  727. ;;;      (#<DTP-LOCATIVE 7346562>
  728. ;;;       (TICL:MACRO TICL:NAMED-LAMBDA (BAR (:DESCRIPTIVE-ARGLIST (A B)))
  729. ;;;           (SYS::*MACROARG* &OPTIONAL SYS::*MACROENVIRONMENT*)
  730. ;;;           (BLOCK BAR ....))
  731. ;;;       #<DTP-LOCATIVE 4710664>
  732. ;;;       (TICL:MACRO TICL:NAMED-LAMBDA (BAR2 (:DESCRIPTIVE-ARGLIST (A B)))
  733. ;;;           (SYS::*MACROARG* &OPTIONAL SYS::*MACROENVIRONMENT*)
  734. ;;;           (BLOCK BAR2 ....))))
  735. #+TI
  736. (progn 
  737.  
  738. ;;; from sys:site;macros.lisp
  739. (eval-when (compile load eval)
  740.   
  741. (DEFMACRO MACRO-DEF? (thing)
  742.   `(AND (CONSP ,thing) (EQ (CAR ,thing) 'TICL::MACRO)))
  743.  
  744. ;; the following macro generates code to check the 'local' environment
  745. ;; for a macro definition for THE SYMBOL <name>. Such a definition would
  746. ;; be set up only by a MACROLET. If a macro definition for <name> is
  747. ;; found, its expander function is returned.
  748.  
  749. (DEFMACRO FIND-LOCAL-DEFINITION (name local-function-environment)
  750.   `(IF ,local-function-environment
  751.        (LET ((vcell (ticl::LOCF (SYMBOL-FUNCTION ,name))))
  752.      (DOLIST (frame  ,local-function-environment)
  753.        ;; <value> is nil or a locative
  754.        (LET ((value (sys::GET-LOCATION-OR-NIL (ticl::LOCF frame)
  755.                           vcell))) 
  756.          (When value (RETURN (CAR value))))))
  757.        nil)))
  758.  
  759.  
  760. ;;;Edited by Reed Hastings         13 Jan 88  16:29
  761. (defun environment-macro (env macro)
  762.   "returns what macro-function would, ie. the expansion function"
  763.   ;;some code picked off macroexpand-1
  764.   (let* ((local-definitions (cadr env))
  765.      (local-def (find-local-definition macro local-definitions)))
  766.     (if (macro-def? local-def)
  767.     (cdr local-def))))
  768.  
  769. ;;;Edited by Reed Hastings         13 Jan 88  16:29
  770. ;;;Edited by Reed Hastings         7 Mar 88  19:07
  771. (defun environment-function (env fn)
  772.   (let* ((local-definitions (cadr env)))
  773.     (dolist (frame local-definitions)
  774.       (let ((val (getf frame
  775.                (ticl::locf (symbol-function fn))
  776.                :not-found-marker)))
  777.     (cond ((eq val :not-found-marker))
  778.           ((functionp val) (return t))
  779.           ((and (listp val)
  780.             (eq (car val) 'ticl::macro))
  781.            (return nil))
  782.           (t
  783.            (error "we are confused")))))))
  784.          
  785.  
  786. ;;;Edited by Reed Hastings         13 Jan 88  16:29
  787. ;;;Edited by Reed Hastings         7 Mar 88  19:07
  788. (defun with-augmented-environment-internal (env functions macros)
  789.   (let ((local-definitions (cadr env))
  790.     (new-local-fns-frame
  791.       (mapcan #'(lambda (fn)
  792.               (list (ticl:locf (symbol-function (car fn)))
  793.                 #'unbound-lexical-function))
  794.           functions))
  795.      (new-local-macros-frame
  796.        (mapcan #'(lambda (m)
  797.                (list (ticl:locf (symbol-function (car m))) (cons 'ticl::macro (cadr m))))
  798.            macros)))
  799.     (when new-local-fns-frame 
  800.       (push new-local-fns-frame local-definitions))
  801.     (when new-local-macros-frame
  802.       (push new-local-macros-frame local-definitions))   
  803.     `(,(car env) ,local-definitions)))
  804.  
  805.  
  806. ;;;Edited by Reed Hastings         7 Mar 88  19:07
  807. (defmacro with-augmented-environment
  808.       ((new-env old-env &key functions macros) &body body)
  809.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  810.                             ,functions
  811.                             ,macros)))
  812.      ,@body))
  813.  
  814. );#+TI
  815.  
  816.  
  817. #+(and dec vax common)
  818. (progn
  819.  
  820. (defmacro with-augmented-environment
  821.       ((new-env old-env &key functions macros) &body body)
  822.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  823.                             ,functions
  824.                             ,macros)))
  825.      ,@body))
  826.  
  827. (defun with-augmented-environment-internal (env functions macros)
  828.   #'(lambda (op &optional (arg nil arg-p))
  829.       (cond ((eq op :macro-function) 
  830.          (unless arg-p (error "Invalid environment use."))
  831.          (lookup-macro-function arg env functions macros))
  832.             (arg-p
  833.          (error "Invalid environment operation: ~S ~S" op arg))
  834.             (t
  835.          (lookup-macro-function op env functions macros)))))
  836.  
  837. (defun lookup-macro-function (name env fns macros)
  838.   (let ((m (assoc name macros)))
  839.     (cond (m                (cadr m))
  840.           ((assoc name fns) :function)
  841.           (env              (funcall env name))
  842.           (t                nil))))
  843.  
  844. (defun environment-macro (env macro)
  845.   (let ((m (and env (funcall env macro))))
  846.     (and (not (eq m :function)) 
  847.          m)))
  848.  
  849. ;;; Nobody calls environment-function.  What would it return, anyway?
  850. );#+(and dec vax common)
  851.  
  852.  
  853. ;;;
  854. ;;; In Golden Common Lisp, the macroexpansion environment is just a list
  855. ;;; of environment entries.  Unless the car of the list is :compiler-menv 
  856. ;;; it is an interpreted environment.  The cadr of each element specifies 
  857. ;;; the type of the element.  The only types that interest us are GCL:MACRO
  858. ;;; and FUNCTION.  In these cases the element is interpreted as follows.
  859. ;;;
  860. ;;; Compiled:
  861. ;;;   (<function-name> <gensym> macroexpansion-function)
  862. ;;;   (<function-name> <fn>)
  863. ;;;   
  864. ;;; Interpreted:
  865. ;;;   (<function-name> GCL:MACRO macroexpansion-function)
  866. ;;;   (<function-name> <fn>)
  867. ;;;   
  868. ;;;   When in the compiler, <fn> is a gensym which will be
  869. ;;;   a variable which bound at run-time to the function.
  870. ;;;   When in the interpreter, <fn> is the actual function.
  871. ;;;   
  872. ;;;
  873. #+gclisp
  874. (progn
  875.  
  876. (defmacro with-augmented-environment
  877.       ((new-env old-env &key functions macros) &body body)
  878.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  879.                             ,functions
  880.                             ,macros)))
  881.      ,@body))
  882.  
  883. (defun with-augmented-environment-internal (env functions macros)
  884.   (let ((new-entries nil))
  885.     (dolist (f functions)
  886.       (push (cons (car f) nil) new-entries))
  887.     (dolist (m macros)
  888.       (push (cons (car m)
  889.           (if (eq :compiler-menv (car env))
  890.               (if (eq (caadr m) 'lisp::lambda)
  891.               `(,(gensym) ,(cadr m))
  892.             `(,(gensym) ,@(cadr m)))
  893.             `(gclisp:MACRO ,@(cadr m))))
  894.           new-entries))
  895.     (if (eq :compiler-menv (car env))
  896.     `(:compiler-menv ,@new-entries ,@(cdr env))
  897.       (append new-entries env))))
  898.  
  899. (defun environment-function (env fn)
  900.   (let ((entry (lisp::lexical-function fn env)))
  901.     (and entry 
  902.      (eq entry 'lisp::lexical-function)
  903.      fn)))
  904.  
  905. (defun environment-macro (env macro)
  906.   (let ((entry (assoc macro (if (eq :compiler-menv (first env))
  907.                  (rest env)
  908.                    env))))
  909.     (and entry
  910.      (consp entry)
  911.      (symbolp (car entry))            ;name
  912.      (symbolp (cadr entry))            ;gcl:macro or gensym
  913.      (nthcdr 2 entry))))
  914.  
  915. );#+gclisp
  916.  
  917.  
  918. ;;;; CMU Common Lisp version of environment frobbing stuff.
  919.  
  920. ;;; In CMU Common Lisp, the environment is represented with a structure
  921. ;;; that holds alists for the functional things, variables, blocks, etc.
  922. ;;; Only the c::lexenv-functions slot is relevent.  It holds:
  923. ;;; Alist (name . what), where What is either a Functional (a local function)
  924. ;;; or a list (MACRO . <function>) (a local macro, with the specifier
  925. ;;; expander.)    Note that Name may be a (SETF <name>) function.
  926.  
  927. #+:CMU
  928. (progn
  929.  
  930. (defmacro with-augmented-environment
  931.       ((new-env old-env &key functions macros) &body body)
  932.   `(let ((,new-env (with-augmented-environment-internal ,old-env
  933.                             ,functions
  934.                             ,macros)))
  935.      ,@body))
  936.  
  937. (defun with-augmented-environment-internal (env functions macros)
  938.   ;; Note: In order to record the correct function definition, we would
  939.   ;; have to create an interpreted closure, but the with-new-definition
  940.   ;; macro down below makes no distinction between flet and labels, so
  941.   ;; we have no idea what to use for the environment.  So we just blow it
  942.   ;; off, 'cause anything real we do would be wrong.  We still have to
  943.   ;; make an entry so we can tell functions from macros.
  944.   (c::make-lexenv :default (or env (c::make-null-environment))
  945.           :functions
  946.           (append (mapcar #'(lambda (f)
  947.                       (cons (car f) (c::make-functional)))
  948.                   functions)
  949.               (mapcar #'(lambda (m)
  950.                       (list* (car m) 'c::macro
  951.                          (coerce (cadr m) 'function)))
  952.                   macros))))
  953.  
  954. (defun environment-function (env fn)
  955.   (when env
  956.     (let ((entry (assoc fn (c::lexenv-functions env) :test #'equal)))
  957.       (and entry
  958.        (c::functional-p (cdr entry))
  959.        (cdr entry)))))
  960.  
  961. (defun environment-macro (env macro)
  962.   (when env
  963.     (let ((entry (assoc macro (c::lexenv-functions env) :test #'eq)))
  964.       (and entry 
  965.        (eq (cadr entry) 'c::macro)
  966.        (function-lambda-expression (cddr entry))))))
  967.  
  968. ); end of #+:CMU
  969.  
  970.  
  971.  
  972. (defmacro with-new-definition-in-environment
  973.       ((new-env old-env macrolet/flet/labels-form) &body body)
  974.   (let ((functions (make-symbol "Functions"))
  975.     (macros (make-symbol "Macros")))
  976.     `(let ((,functions ())
  977.        (,macros ()))
  978.        (ecase (car ,macrolet/flet/labels-form)
  979.      ((flet labels)
  980.       (dolist (fn (cadr ,macrolet/flet/labels-form))
  981.         (push fn ,functions)))
  982.      ((macrolet)
  983.       (dolist (mac (cadr ,macrolet/flet/labels-form))
  984.         (push (list (car mac)
  985.             (convert-macro-to-lambda (cadr mac)
  986.                          (cddr mac)
  987.                          (string (car mac))))
  988.           ,macros))))
  989.        (with-augmented-environment
  990.           (,new-env ,old-env :functions ,functions :macros ,macros)
  991.      ,@body))))
  992.  
  993. #-Genera
  994. (defun convert-macro-to-lambda (llist body &optional (name "Dummy Macro"))
  995.   (let ((gensym (make-symbol name)))
  996.     (eval `(defmacro ,gensym ,llist ,@body))
  997.     (macro-function gensym)))
  998.  
  999. #+Genera
  1000. (defun convert-macro-to-lambda (llist body &optional (name "Dummy Macro"))
  1001.   (si:defmacro-1
  1002.     'sys:named-lambda 'sys:special (make-symbol name) llist body))
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008. ;;;
  1009. ;;; Now comes the real walker.
  1010. ;;;
  1011. ;;; As the walker walks over the code, it communicates information to itself
  1012. ;;; about the walk.  This information includes the walk function, variable
  1013. ;;; bindings, declarations in effect etc.  This information is inherently
  1014. ;;; lexical, so the walker passes it around in the actual environment the
  1015. ;;; walker passes to macroexpansion functions.  This is what makes the
  1016. ;;; nested-walk-form facility work properly.
  1017. ;;;
  1018. (defmacro walker-environment-bind ((var env &rest key-args)
  1019.                       &body body)
  1020.   `(with-augmented-environment
  1021.      (,var ,env :macros (walker-environment-bind-1 ,env ,.key-args))
  1022.      .,body))
  1023.  
  1024. (defvar *key-to-walker-environment* (gensym))
  1025.  
  1026. (defun env-lock (env)
  1027.   (environment-macro env *key-to-walker-environment*))
  1028.  
  1029. (defun walker-environment-bind-1 (env &key (walk-function nil wfnp)
  1030.                        (walk-form nil wfop)
  1031.                        (declarations nil decp)
  1032.                        (lexical-variables nil lexp))
  1033.   (let ((lock (environment-macro env *key-to-walker-environment*)))
  1034.     (list
  1035.       (list *key-to-walker-environment*
  1036.         (list (if wfnp walk-function     (car lock))
  1037.           (if wfop walk-form         (cadr lock))
  1038.           (if decp declarations      (caddr lock))
  1039.           (if lexp lexical-variables (cadddr lock)))))))
  1040.           
  1041. (defun env-walk-function (env)
  1042.   (car (env-lock env)))
  1043.  
  1044. (defun env-walk-form (env)
  1045.   (cadr (env-lock env)))
  1046.  
  1047. (defun env-declarations (env)
  1048.   (caddr (env-lock env)))
  1049.  
  1050. (defun env-lexical-variables (env)
  1051.   (cadddr (env-lock env)))
  1052.  
  1053.  
  1054. (defun note-declaration (declaration env)
  1055.   (push declaration (caddr (env-lock env))))
  1056.  
  1057. (defun note-lexical-binding (thing env)
  1058.   (push (list thing :lexical-var) (cadddr (env-lock env))))
  1059.  
  1060.  
  1061. (defun VARIABLE-LEXICAL-P (var env)
  1062.   (let ((entry (member var (env-lexical-variables env) :key #'car)))
  1063.     (when (eq (cadar entry) :lexical-var)
  1064.       entry)))
  1065.  
  1066. (defun variable-symbol-macro-p (var env)
  1067.   (let ((entry (member var (env-lexical-variables env) :key #'car)))
  1068.     (when (eq (cadar entry) :macro)
  1069.       entry)))
  1070.  
  1071.  
  1072. (defvar *VARIABLE-DECLARATIONS* (list 'special))
  1073.  
  1074. (defun VARIABLE-DECLARATION (declaration var env)
  1075.   (if (not (member declaration *variable-declarations*))
  1076.       (error "~S is not a reckognized variable declaration." declaration)
  1077.       (let ((id (or (variable-lexical-p var env) var)))
  1078.     (dolist (decl (env-declarations env))
  1079.       (when (and (eq (car decl) declaration)
  1080.              (eq (cadr decl) id))
  1081.         (return decl))))))
  1082.  
  1083. (defun VARIABLE-SPECIAL-P (var env)
  1084.   (or (not (null (variable-declaration 'special var env)))
  1085.       (variable-globally-special-p var)))
  1086.  
  1087. ;;;
  1088. ;;; VARIABLE-GLOBALLY-SPECIAL-P is used to ask if a variable has been
  1089. ;;; declared globally special.  Any particular CommonLisp implementation
  1090. ;;; should customize this function accordingly and send their customization
  1091. ;;; back.
  1092. ;;;
  1093. ;;; The default version of variable-globally-special-p is probably pretty
  1094. ;;; slow, so it uses *globally-special-variables* as a cache to remember
  1095. ;;; variables that it has already figured out are globally special.
  1096. ;;;
  1097. ;;; This would need to be reworked if an unspecial declaration got added to
  1098. ;;; Common Lisp.
  1099. ;;;
  1100. ;;; Common Lisp nit:
  1101. ;;;   variable-globally-special-p should be defined in Common Lisp.
  1102. ;;;
  1103. #-(or Genera Cloe-Runtime Lucid Xerox Excl KCL IBCL (and dec vax common) :CMU HP-HPLabs
  1104.       GCLisp TI pyramid)
  1105. (defvar *globally-special-variables* '(*evalhook* *applyhook* *macroexpand-hook*))
  1106.  
  1107. (defun variable-globally-special-p (symbol)
  1108.   #+Genera                      (si:special-variable-p symbol)
  1109.   #+Cloe-Runtime        (compiler::specialp symbol)
  1110.   #+Lucid                       (lucid::proclaimed-special-p symbol)
  1111.   #+TI                          (get symbol 'special)
  1112.   #+Xerox                       (il:variable-globally-special-p symbol)
  1113.   #+(and dec vax common)        (get symbol 'system::globally-special)
  1114.   #+(or KCL IBCL)               (si:specialp symbol)
  1115.   #+excl                        (get symbol 'excl::.globally-special.)
  1116.   #+:CMU            (eq (ext:info variable kind symbol) :special)
  1117.   #+HP-HPLabs                   (member (get symbol 'impl:vartype)
  1118.                     '(impl:fluid impl:global)
  1119.                     :test #'eq)
  1120.   #+:GCLISP                     (gclisp::special-p symbol)
  1121.   #+pyramid            (or (get symbol 'lisp::globally-special)
  1122.                     (get symbol
  1123.                      'clc::globally-special-in-compiler))
  1124.   #+:CORAL                      (ccl::proclaimed-special-p symbol)
  1125.   #-(or Genera Cloe-Runtime Lucid Xerox Excl KCL IBCL (and dec vax common) :CMU HP-HPLabs
  1126.     GCLisp TI pyramid :CORAL)
  1127.   (or (not (null (member symbol *globally-special-variables* :test #'eq)))
  1128.       (when (eval `(flet ((ref () ,symbol))
  1129.              (let ((,symbol '#,(list nil)))
  1130.                (and (boundp ',symbol) (eq ,symbol (ref))))))
  1131.     (push symbol *globally-special-variables*)
  1132.     t)))
  1133.  
  1134.  
  1135.   ;;   
  1136. ;;;;;; Handling of special forms (the infamous 24).
  1137.   ;;
  1138. ;;;
  1139. ;;; and I quote...
  1140. ;;; 
  1141. ;;;     The set of special forms is purposely kept very small because
  1142. ;;;     any program analyzing program (read code walker) must have
  1143. ;;;     special knowledge about every type of special form. Such a
  1144. ;;;     program needs no special knowledge about macros...
  1145. ;;;
  1146. ;;; So all we have to do here is a define a way to store and retrieve
  1147. ;;; templates which describe how to walk the 24 special forms and we are all
  1148. ;;; set...
  1149. ;;;
  1150. ;;; Well, its a nice concept, and I have to admit to being naive enough that
  1151. ;;; I believed it for a while, but not everyone takes having only 24 special
  1152. ;;; forms as seriously as might be nice.  There are (at least) 3 ways to
  1153. ;;; lose:
  1154. ;;
  1155. ;;;   1 - Implementation x implements a Common Lisp special form as a macro
  1156. ;;;       which expands into a special form which:
  1157. ;;;         - Is a common lisp special form (not likely)
  1158. ;;;         - Is not a common lisp special form (on the 3600 IF --> COND).
  1159. ;;;
  1160. ;;;     * We can safe ourselves from this case (second subcase really) by
  1161. ;;;       checking to see if there is a template defined for something
  1162. ;;;       before we check to see if we we can macroexpand it.
  1163. ;;;
  1164. ;;;   2 - Implementation x implements a Common Lisp macro as a special form.
  1165. ;;;
  1166. ;;;     * This is a screw, but not so bad, we save ourselves from it by
  1167. ;;;       defining extra templates for the macros which are *likely* to
  1168. ;;;       be implemented as special forms.  (DO, DO* ...)
  1169. ;;;
  1170. ;;;   3 - Implementation x has a special form which is not on the list of
  1171. ;;;       Common Lisp special forms.
  1172. ;;;
  1173. ;;;     * This is a bad sort of a screw and happens more than I would like
  1174. ;;;       to think, especially in the implementations which provide more
  1175. ;;;       than just Common Lisp (3600, Xerox etc.).
  1176. ;;;       The fix is not terribly staisfactory, but will have to do for
  1177. ;;;       now.  There is a hook in get walker-template which can get a
  1178. ;;;       template from the implementation's own walker.  That template
  1179. ;;;       has to be converted, and so it may be that the right way to do
  1180. ;;;       this would actually be for that implementation to provide an
  1181. ;;;       interface to its walker which looks like the interface to this
  1182. ;;;       walker.
  1183. ;;;
  1184.  
  1185. (eval-when (compile load eval)
  1186.  
  1187. (defmacro get-walker-template-internal (x) ;Has to be inside eval-when because
  1188.   `(get ,x 'walker-template))           ;Golden Common Lisp doesn't hack
  1189.                        ;compile time definition of macros
  1190.                        ;right for setf.
  1191.  
  1192. (defmacro define-walker-template
  1193.       (name &optional (template '(nil repeat (eval))))
  1194.   `(eval-when (load eval)
  1195.      (setf (get-walker-template-internal ',name) ',template)))
  1196. )
  1197.  
  1198. (defun get-walker-template (x)
  1199.   (cond ((symbolp x)
  1200.      (or (get-walker-template-internal x)
  1201.          (get-implementation-dependent-walker-template x)))
  1202.     ((and (listp x) (eq (car x) 'lambda))
  1203.      '(lambda repeat (eval)))
  1204.     (t
  1205.      (error "Can't get template for ~S" x))))
  1206.  
  1207. (defun get-implementation-dependent-walker-template (x)
  1208.   (declare (ignore x))
  1209.   ())
  1210.  
  1211.  
  1212.   ;;   
  1213. ;;;;;; The actual templates
  1214.   ;;   
  1215.  
  1216. (define-walker-template BLOCK                (NIL NIL REPEAT (EVAL)))
  1217. (define-walker-template CATCH                (NIL EVAL REPEAT (EVAL)))
  1218. (define-walker-template COMPILER-LET         walk-compiler-let)
  1219. (define-walker-template DECLARE              walk-unexpected-declare)
  1220. (define-walker-template EVAL-WHEN            (NIL QUOTE REPEAT (EVAL)))
  1221. (define-walker-template FLET                 walk-flet)
  1222. (define-walker-template FUNCTION             (NIL CALL))
  1223. (define-walker-template GO                   (NIL QUOTE))
  1224. (define-walker-template IF                   walk-if)
  1225. (define-walker-template LABELS               walk-labels)
  1226. (define-walker-template LAMBDA               walk-lambda)
  1227. (define-walker-template LET                  walk-let)
  1228. (define-walker-template LET*                 walk-let*)
  1229. (define-walker-template MACROLET             walk-macrolet)
  1230. (define-walker-template MULTIPLE-VALUE-CALL  (NIL EVAL REPEAT (EVAL)))
  1231. (define-walker-template MULTIPLE-VALUE-PROG1 (NIL RETURN REPEAT (EVAL)))
  1232. (define-walker-template MULTIPLE-VALUE-SETQ  walk-multiple-value-setq)
  1233. (define-walker-template MULTIPLE-VALUE-BIND  walk-multiple-value-bind)
  1234. (define-walker-template PROGN                (NIL REPEAT (EVAL)))
  1235. (define-walker-template PROGV                (NIL EVAL EVAL REPEAT (EVAL)))
  1236. (define-walker-template QUOTE                (NIL QUOTE))
  1237. (define-walker-template RETURN-FROM          (NIL QUOTE REPEAT (RETURN)))
  1238. (define-walker-template SETQ                 walk-setq)
  1239. (define-walker-template SYMBOL-MACROLET      walk-symbol-macrolet)
  1240. (define-walker-template TAGBODY              walk-tagbody)
  1241. (define-walker-template THE                  (NIL QUOTE EVAL))
  1242. (define-walker-template THROW                (NIL EVAL EVAL))
  1243. (define-walker-template UNWIND-PROTECT       (NIL RETURN REPEAT (EVAL)))
  1244.  
  1245. ;;; The new special form.
  1246. ;(define-walker-template pcl::LOAD-TIME-EVAL       (NIL EVAL))
  1247.  
  1248. ;;;
  1249. ;;; And the extra templates...
  1250. ;;;
  1251. (define-walker-template DO      walk-do)
  1252. (define-walker-template DO*     walk-do*)
  1253. (define-walker-template PROG    walk-prog)
  1254. (define-walker-template PROG*   walk-prog*)
  1255. (define-walker-template COND    (NIL REPEAT ((TEST REPEAT (EVAL)))))
  1256.  
  1257. #+Genera
  1258. (progn
  1259.   (define-walker-template zl::named-lambda walk-named-lambda)
  1260.   (define-walker-template SCL:LETF walk-let)
  1261.   (define-walker-template SCL:LETF* walk-let*)
  1262.   )
  1263.  
  1264. #+Lucid
  1265. (progn
  1266.   (define-walker-template #+LCL3.0 lucid-common-lisp:named-lambda
  1267.               #-LCL3.0 sys:named-lambda walk-named-lambda)
  1268.   )
  1269.  
  1270. #+(or KCL IBCL)
  1271. (progn
  1272.   (define-walker-template lambda-block walk-named-lambda);Not really right,
  1273.                              ;we don't hack block
  1274.                                  ;names anyways.
  1275.   )
  1276.  
  1277. #+TI
  1278. (progn
  1279.   (define-walker-template TICL::LET-IF walk-let-if)
  1280.   )
  1281.  
  1282. #+:Coral
  1283. (progn
  1284.   (define-walker-template ccl:%stack-block walk-let)
  1285.   )
  1286. #+:cltl2
  1287. (define-walker-template LOCALLY             walk-locally)
  1288.  
  1289.  
  1290.  
  1291. (defun WALK-FORM (form
  1292.           &optional environment
  1293.                 (walk-function
  1294.                   #'(lambda (subform context env)
  1295.                   (declare (ignore context env))
  1296.                   subform)))
  1297.   (walker-environment-bind (new-env environment :walk-function walk-function)
  1298.     (walk-form-internal form :eval new-env)))
  1299.  
  1300. ;;;
  1301. ;;; nested-walk-form provides an interface that allows nested macros, each
  1302. ;;; of which must walk their body to just do one walk of the body of the
  1303. ;;; inner macro.  That inner walk is done with a walk function which is the
  1304. ;;; composition of the two walk functions.
  1305. ;;;
  1306. ;;; This facility works by having the walker annotate the environment that
  1307. ;;; it passes to macroexpand-1 to know which form is being macroexpanded.
  1308. ;;; If then the &whole argument to the macroexpansion function is eq to
  1309. ;;; the env-walk-form of the environment, nested-walk-form can be certain
  1310. ;;; that there are no intervening layers and that a nested walk is alright.
  1311. ;;;
  1312. ;;; There are some semantic problems with this facility.  In particular, if
  1313. ;;; the outer walk function returns T as its walk-no-more-p value, this will
  1314. ;;; prevent the inner walk function from getting a chance to walk the subforms
  1315. ;;; of the form.  This is almost never what you want, since it destroys the
  1316. ;;; equivalence between this nested-walk-form function and two seperate
  1317. ;;; walk-forms.
  1318. ;;;
  1319. (defun NESTED-WALK-FORM (whole
  1320.              form
  1321.              &optional environment
  1322.                    (walk-function
  1323.                      #'(lambda (subform context env)
  1324.                      (declare (ignore context env))
  1325.                      subform)))
  1326.   (if (eq whole (env-walk-form environment))
  1327.       (let ((outer-walk-function (env-walk-function environment)))
  1328.     (throw whole
  1329.       (walk-form
  1330.         form
  1331.         environment
  1332.         #'(lambda (f c e)
  1333.         ;; First loop to make sure the inner walk function
  1334.         ;; has done all it wants to do with this form.
  1335.         ;; Basically, what we are doing here is providing
  1336.         ;; the same contract walk-form-internal normally
  1337.         ;; provides to the inner walk function.
  1338.         (let ((inner-result nil)
  1339.               (inner-no-more-p nil)
  1340.               (outer-result nil)
  1341.               (outer-no-more-p nil))
  1342.           (loop
  1343.             (multiple-value-setq (inner-result inner-no-more-p)
  1344.                      (funcall walk-function f c e))
  1345.             (cond (inner-no-more-p (return))
  1346.               ((not (eq inner-result f)))
  1347.               ((not (consp inner-result)) (return))
  1348.               ((get-walker-template (car inner-result)) (return))
  1349.               (t
  1350.                (multiple-value-bind (expansion macrop)
  1351.                    (walker-environment-bind
  1352.                      (new-env e :walk-form inner-result)
  1353.                  (macroexpand-1 inner-result new-env))
  1354.                  (if macrop
  1355.                  (setq inner-result expansion)
  1356.                  (return)))))
  1357.             (setq f inner-result))
  1358.           (multiple-value-setq (outer-result outer-no-more-p)
  1359.                        (funcall outer-walk-function
  1360.                         inner-result
  1361.                         c
  1362.                         e))
  1363.           (values outer-result
  1364.               (and inner-no-more-p outer-no-more-p)))))))
  1365.       (walk-form form environment walk-function)))
  1366.  
  1367. ;;;
  1368. ;;; WALK-FORM-INTERNAL is the main driving function for the code walker. It
  1369. ;;; takes a form and the current context and walks the form calling itself or
  1370. ;;; the appropriate template recursively.
  1371. ;;;
  1372. ;;;   "It is recommended that a program-analyzing-program process a form
  1373. ;;;    that is a list whose car is a symbol as follows:
  1374. ;;;
  1375. ;;;     1. If the program has particular knowledge about the symbol,
  1376. ;;;        process the form using special-purpose code.  All of the
  1377. ;;;        standard special forms should fall into this category.
  1378. ;;;     2. Otherwise, if macro-function is true of the symbol apply
  1379. ;;;        either macroexpand or macroexpand-1 and start over.
  1380. ;;;     3. Otherwise, assume it is a function call. "
  1381. ;;;     
  1382.  
  1383. (defvar walk-form-expand-macros-p nil)
  1384.  
  1385. (defun walk-form-internal (form context env)
  1386.   ;; First apply the walk-function to perform whatever translation
  1387.   ;; the user wants to this form.  If the second value returned
  1388.   ;; by walk-function is T then we don't recurse...
  1389.   (catch form
  1390.     (multiple-value-bind (newform walk-no-more-p)
  1391.       (funcall (env-walk-function env) form context env)
  1392.       (catch newform
  1393.     (cond
  1394.      (walk-no-more-p newform)
  1395.      ((not (eq form newform))
  1396.       (walk-form-internal newform context env))
  1397.      ((not (consp newform))
  1398.       (let ((symmac (car (variable-symbol-macro-p newform env))))
  1399.         (if symmac
  1400.         (let ((newnewform (walk-form-internal (cddr symmac)
  1401.                               context env)))
  1402.           (if (eq newnewform (cddr symmac))
  1403.               (if walk-form-expand-macros-p newnewform newform)
  1404.               newnewform))
  1405.         newform)))
  1406.      (t
  1407.       (let* ((fn (car newform))
  1408.          (template (get-walker-template fn)))
  1409.         (if template
  1410.         (if (symbolp template)
  1411.             (funcall template newform context env)
  1412.             (walk-template newform template context env))
  1413.         (multiple-value-bind
  1414.             (newnewform macrop)
  1415.             (walker-environment-bind
  1416.             (new-env env :walk-form newform)
  1417.               (macroexpand-1 newform new-env))
  1418.           (cond
  1419.            (macrop
  1420.             (let ((newnewnewform (walk-form-internal newnewform context
  1421.                                  env)))
  1422.               (if (eq newnewnewform newnewform)
  1423.               (if walk-form-expand-macros-p newnewform newform)
  1424.               newnewnewform)))
  1425.            ((and (symbolp fn)
  1426.              (not (fboundp fn))
  1427.              (special-form-p fn))
  1428.             (error
  1429.              "~S is a special form, not defined in the CommonLisp.~%~
  1430.               manual This code walker doesn't know how to walk it.~%~
  1431.               Define a template for this special form and try again."
  1432.              fn))
  1433.            (t
  1434.             ;; Otherwise, walk the form as if its just a standard 
  1435.             ;; functioncall using a template for standard function
  1436.             ;; call.
  1437.             (walk-template
  1438.              newnewform '(call repeat (eval)) context env))))))))))))
  1439.  
  1440. (defun walk-template (form template context env)
  1441.   (if (atom template)
  1442.       (ecase template
  1443.         ((EVAL FUNCTION TEST EFFECT RETURN)
  1444.          (walk-form-internal form :EVAL env))
  1445.         ((QUOTE NIL) form)
  1446.         (SET
  1447.           (walk-form-internal form :SET env))
  1448.         ((LAMBDA CALL)
  1449.      (cond ((or (symbolp form)
  1450.             (and (listp form)
  1451.              (= (length (the list form)) 2)
  1452.              (eq (car form) 'setf)))
  1453.         form)
  1454.            #+Lispm
  1455.            ((sys:validate-function-spec form) form)
  1456.            (t (walk-form-internal form context env)))))
  1457.       (case (car template)
  1458.         (REPEAT
  1459.           (walk-template-handle-repeat form
  1460.                                        (cdr template)
  1461.                        ;; For the case where nothing happens
  1462.                        ;; after the repeat optimize out the
  1463.                        ;; call to length.
  1464.                        (if (null (cddr template))
  1465.                        ()
  1466.                        (nthcdr (- (length (the list form))
  1467.                               (length
  1468.                             (the list
  1469.                                                              (cddr template))))
  1470.                            form))
  1471.                                        context
  1472.                        env))
  1473.         (IF
  1474.       (walk-template form
  1475.              (if (if (listp (cadr template))
  1476.                  (eval (cadr template))
  1477.                  (funcall (cadr template) form))
  1478.                  (caddr template)
  1479.                  (cadddr template))
  1480.              context
  1481.              env))
  1482.         (REMOTE
  1483.           (walk-template form (cadr template) context env))
  1484.         (otherwise
  1485.           (cond ((atom form) form)
  1486.                 (t (recons form
  1487.                            (walk-template
  1488.                  (car form) (car template) context env)
  1489.                            (walk-template
  1490.                  (cdr form) (cdr template) context env))))))))
  1491.  
  1492. (defun walk-template-handle-repeat (form template stop-form context env)
  1493.   (if (eq form stop-form)
  1494.       (walk-template form (cdr template) context env)
  1495.       (walk-template-handle-repeat-1 form
  1496.                      template
  1497.                      (car template)
  1498.                      stop-form
  1499.                      context
  1500.                      env)))
  1501.  
  1502. (defun walk-template-handle-repeat-1 (form template repeat-template
  1503.                        stop-form context env)
  1504.   (cond ((null form) ())
  1505.         ((eq form stop-form)
  1506.          (if (null repeat-template)
  1507.              (walk-template stop-form (cdr template) context env)       
  1508.              (error "While handling repeat:
  1509.                      ~%~Ran into stop while still in repeat template.")))
  1510.         ((null repeat-template)
  1511.          (walk-template-handle-repeat-1
  1512.        form template (car template) stop-form context env))
  1513.         (t
  1514.          (recons form
  1515.                  (walk-template (car form) (car repeat-template) context env)
  1516.                  (walk-template-handle-repeat-1 (cdr form)
  1517.                         template
  1518.                         (cdr repeat-template)
  1519.                         stop-form
  1520.                         context
  1521.                         env)))))
  1522.  
  1523. (defun walk-repeat-eval (form env)
  1524.   (and form
  1525.        (recons form
  1526.            (walk-form-internal (car form) :eval env)
  1527.            (walk-repeat-eval (cdr form) env))))
  1528.  
  1529. (defun recons (x car cdr)
  1530.   (if (or (not (eq (car x) car))
  1531.           (not (eq (cdr x) cdr)))
  1532.       (cons car cdr)
  1533.       x))
  1534.  
  1535. (defun relist (x &rest args)
  1536.   (if (null args)
  1537.       nil
  1538.       (relist-internal x args nil)))
  1539.  
  1540. (defun relist* (x &rest args)
  1541.   (relist-internal x args 't))
  1542.  
  1543. (defun relist-internal (x args *p)
  1544.   (if (null (cdr args))
  1545.       (if *p
  1546.       (car args)
  1547.       (recons x (car args) nil))
  1548.       (recons x
  1549.           (car args)
  1550.           (relist-internal (cdr x) (cdr args) *p))))
  1551.  
  1552.  
  1553.   ;;   
  1554. ;;;;;; Special walkers
  1555.   ;;
  1556.  
  1557. (defun walk-declarations (body fn env
  1558.                    &optional doc-string-p declarations old-body
  1559.                    &aux (form (car body)) macrop new-form)
  1560.   (cond ((and (stringp form)            ;might be a doc string
  1561.               (cdr body)            ;isn't the returned value
  1562.               (null doc-string-p)        ;no doc string yet
  1563.               (null declarations))        ;no declarations yet
  1564.          (recons body
  1565.                  form
  1566.                  (walk-declarations (cdr body) fn env t)))
  1567.         ((and (listp form) (eq (car form) 'declare))
  1568.          ;; Got ourselves a real live declaration.  Record it, look for more.
  1569.          (dolist (declaration (cdr form))
  1570.        (let ((type (car declaration))
  1571.          (name (cadr declaration))
  1572.          (args (cddr declaration)))
  1573.          (if (member type *variable-declarations*)
  1574.          (note-declaration `(,type
  1575.                      ,(or (variable-lexical-p name env) name)
  1576.                      ,.args)
  1577.                    env)
  1578.          (note-declaration declaration env))
  1579.          (push declaration declarations)))
  1580.          (recons body
  1581.                  form
  1582.                  (walk-declarations
  1583.            (cdr body) fn env doc-string-p declarations)))
  1584.         ((and form
  1585.           (listp form)
  1586.           (null (get-walker-template (car form)))
  1587.           (progn
  1588.         (multiple-value-setq (new-form macrop)
  1589.                      (macroexpand-1 form env))
  1590.         macrop))
  1591.      ;; This form was a call to a macro.  Maybe it expanded
  1592.      ;; into a declare?  Recurse to find out.
  1593.      (walk-declarations (recons body new-form (cdr body))
  1594.                 fn env doc-string-p declarations
  1595.                 (or old-body body)))
  1596.     (t
  1597.      ;; Now that we have walked and recorded the declarations,
  1598.      ;; call the function our caller provided to expand the body.
  1599.      ;; We call that function rather than passing the real-body
  1600.      ;; back, because we are RECONSING up the new body.
  1601.      (funcall fn (or old-body body) env))))
  1602.  
  1603.  
  1604. (defun walk-unexpected-declare (form context env)
  1605.   (declare (ignore context env))
  1606.   (warn "Encountered declare ~S in a place where a declare was not expected."
  1607.     form)
  1608.   form)
  1609.  
  1610. (defun walk-arglist (arglist context env &optional (destructuringp nil)
  1611.                      &aux arg)
  1612.   (cond ((null arglist) ())
  1613.         ((symbolp (setq arg (car arglist)))
  1614.          (or (member arg lambda-list-keywords :test #'eq)
  1615.              (note-lexical-binding arg env))
  1616.          (recons arglist
  1617.                  arg
  1618.                  (walk-arglist (cdr arglist)
  1619.                                context
  1620.                    env
  1621.                                (and destructuringp
  1622.                     (not (member arg
  1623.                          lambda-list-keywords
  1624.                                                  :test #'eq))))))
  1625.         ((consp arg)
  1626.          (prog1
  1627.          (recons arglist
  1628.              (if destructuringp
  1629.              (walk-arglist arg context env destructuringp)
  1630.              (relist* arg
  1631.                   (car arg)
  1632.                   (walk-form-internal (cadr arg) :eval env)
  1633.                   (cddr arg)))
  1634.              (walk-arglist (cdr arglist) context env nil))
  1635.        (if (symbolp (car arg))
  1636.            (note-lexical-binding (car arg) env)
  1637.            (note-lexical-binding (cadar arg) env))
  1638.        (or (null (cddr arg))
  1639.            (not (symbolp (caddr arg)))
  1640.            (note-lexical-binding (caddr arg) env))))
  1641.     (t
  1642.      (error "Can't understand something in the arglist ~S" arglist))))
  1643.  
  1644. (defun walk-let (form context env)
  1645.   (walk-let/let* form context env nil))
  1646.  
  1647. (defun walk-let* (form context env)
  1648.   (walk-let/let* form context env t))
  1649.  
  1650. (defun walk-prog (form context env)
  1651.   (walk-prog/prog* form context env nil))
  1652.  
  1653. (defun walk-prog* (form context env)
  1654.   (walk-prog/prog* form context env t))
  1655.  
  1656. (defun walk-do (form context env)
  1657.   (walk-do/do* form context env nil))
  1658.  
  1659. (defun walk-do* (form context env)
  1660.   (walk-do/do* form context env t))
  1661.  
  1662. (defun walk-let/let* (form context old-env sequentialp)
  1663.   (walker-environment-bind (new-env old-env)
  1664.     (let* ((let/let* (car form))
  1665.        (bindings (cadr form))
  1666.        (body (cddr form))
  1667.        (walked-bindings 
  1668.          (walk-bindings-1 bindings
  1669.                   old-env
  1670.                   new-env
  1671.                   context
  1672.                   sequentialp))
  1673.        (walked-body
  1674.          (walk-declarations body #'walk-repeat-eval new-env)))
  1675.       (relist*
  1676.     form let/let* walked-bindings walked-body))))
  1677.  
  1678. #+cltl2(defun walk-locally (form context env )
  1679.          (declare (ignore context ))
  1680.          
  1681.          (let* ((locally (car form))
  1682.             
  1683.             (body (cddr form))
  1684.             
  1685.             (walked-body
  1686.              (walk-declarations body #'walk-repeat-eval env)))
  1687.            (relist*
  1688.         form locally  walked-body)))
  1689.  
  1690.  
  1691.  
  1692. (defun walk-prog/prog* (form context old-env sequentialp)
  1693.   (walker-environment-bind (new-env old-env)
  1694.     (let* ((possible-block-name (second form))
  1695.        (blocked-prog (and (symbolp possible-block-name)
  1696.                   (not (eq possible-block-name 'nil)))))
  1697.       (multiple-value-bind (let/let* block-name bindings body)
  1698.       (if blocked-prog
  1699.           (values (car form) (cadr form) (caddr form) (cdddr form))
  1700.           (values (car form) nil         (cadr  form) (cddr  form)))
  1701.     (let* ((walked-bindings 
  1702.          (walk-bindings-1 bindings
  1703.                   old-env
  1704.                   new-env
  1705.                   context
  1706.                   sequentialp))
  1707.            (walked-body
  1708.          (walk-declarations 
  1709.            body
  1710.            #'(lambda (real-body real-env)
  1711.                (walk-tagbody-1 real-body context real-env))
  1712.            new-env)))
  1713.       (if block-name
  1714.           (relist*
  1715.         form let/let* block-name walked-bindings walked-body)
  1716.           (relist*
  1717.         form let/let* walked-bindings walked-body)))))))
  1718.  
  1719. (defun walk-do/do* (form context old-env sequentialp)
  1720.   (walker-environment-bind (new-env old-env)
  1721.     (let* ((do/do* (car form))
  1722.        (bindings (cadr form))
  1723.        (end-test (caddr form))
  1724.        (body (cdddr form))
  1725.        (walked-bindings (walk-bindings-1 bindings
  1726.                          old-env
  1727.                          new-env
  1728.                          context
  1729.                          sequentialp))
  1730.        (walked-body
  1731.          (walk-declarations body #'walk-repeat-eval new-env)))
  1732.       (relist* form
  1733.            do/do*
  1734.            (walk-bindings-2 bindings walked-bindings context new-env)
  1735.            (walk-template end-test '(test repeat (eval)) context new-env)
  1736.            walked-body))))
  1737.  
  1738. (defun walk-let-if (form context env)
  1739.   (let ((test (cadr form))
  1740.     (bindings (caddr form))
  1741.     (body (cdddr form)))
  1742.     (walk-form-internal
  1743.       `(let ()
  1744.      (declare (special ,@(mapcar #'(lambda (x) (if (listp x) (car x) x))
  1745.                      bindings)))
  1746.      (flet ((.let-if-dummy. () ,@body))
  1747.        (if ,test
  1748.            (let ,bindings (.let-if-dummy.))
  1749.            (.let-if-dummy.))))
  1750.       context
  1751.       env)))
  1752.  
  1753. (defun walk-multiple-value-setq (form context env)
  1754.   (let ((vars (cadr form)))
  1755.     (if (some #'(lambda (var)
  1756.           (variable-symbol-macro-p var env))
  1757.           vars)
  1758.     (let* ((expanded
  1759.                  (let ((sets NIL)
  1760.                        (temps NIL)
  1761.                        (temp NIL))
  1762.                    (dolist (var vars)
  1763.                      (setf temp (gensym))
  1764.                      (push `(setq ,var ,temp) sets)
  1765.                      (push temp temps))
  1766.                   `(multiple-value-bind
  1767.                       ,(nreverse temps)
  1768.                       ,(caddr form)
  1769.                      ,@(nreverse sets))))
  1770.            (walked (walk-form-internal expanded context env)))
  1771.       (if (eq walked expanded)
  1772.           form
  1773.           walked))
  1774.     (walk-template form '(nil (repeat (set)) eval) context env))))
  1775.  
  1776. (defun walk-multiple-value-bind (form context old-env)
  1777.   (walker-environment-bind (new-env old-env)
  1778.     (let* ((mvb (car form))
  1779.        (bindings (cadr form))
  1780.        (mv-form (walk-template (caddr form) 'eval context old-env))
  1781.        (body (cdddr form))
  1782.        walked-bindings
  1783.        (walked-body
  1784.          (walk-declarations 
  1785.            body
  1786.            #'(lambda (real-body real-env)
  1787.            (setq walked-bindings
  1788.              (walk-bindings-1 bindings
  1789.                       old-env
  1790.                       new-env
  1791.                       context
  1792.                       nil))
  1793.            (walk-repeat-eval real-body real-env))
  1794.            new-env)))
  1795.       (relist* form mvb walked-bindings mv-form walked-body))))
  1796.  
  1797. (defun walk-bindings-1 (bindings old-env new-env context sequentialp)
  1798.   (and bindings
  1799.        (let ((binding (car bindings)))
  1800.          (recons bindings
  1801.                  (if (symbolp binding)
  1802.                      (prog1 binding
  1803.                             (note-lexical-binding binding new-env))
  1804.                      (prog1 (relist* binding
  1805.                      (car binding)
  1806.                      (walk-form-internal (cadr binding)
  1807.                              context
  1808.                              (if sequentialp
  1809.                                  new-env
  1810.                                  old-env))
  1811.                      (cddr binding))    ;save cddr for DO/DO*
  1812.                                 ;it is the next value
  1813.                                 ;form. Don't walk it
  1814.                                 ;now though.
  1815.                             (note-lexical-binding (car binding) new-env)))
  1816.                  (walk-bindings-1 (cdr bindings)
  1817.                   old-env
  1818.                   new-env
  1819.                   context
  1820.                   sequentialp)))))
  1821.  
  1822. (defun walk-bindings-2 (bindings walked-bindings context env)
  1823.   (and bindings
  1824.        (let ((binding (car bindings))
  1825.              (walked-binding (car walked-bindings)))
  1826.          (recons bindings
  1827.          (if (symbolp binding)
  1828.              binding
  1829.              (relist* binding
  1830.                   (car walked-binding)
  1831.                   (cadr walked-binding)
  1832.                   (walk-template (cddr binding)
  1833.                          '(eval)
  1834.                          context
  1835.                          env)))         
  1836.                  (walk-bindings-2 (cdr bindings)
  1837.                   (cdr walked-bindings)
  1838.                   context
  1839.                   env)))))
  1840.  
  1841. (defun walk-lambda (form context old-env)
  1842.   (walker-environment-bind (new-env old-env)
  1843.     (let* ((arglist (cadr form))
  1844.            (body (cddr form))
  1845.            (walked-arglist (walk-arglist arglist context new-env))
  1846.            (walked-body
  1847.              (walk-declarations body #'walk-repeat-eval new-env)))
  1848.       (relist* form
  1849.                (car form)
  1850.            walked-arglist
  1851.                walked-body))))
  1852.  
  1853. (defun walk-named-lambda (form context old-env)
  1854.   (walker-environment-bind (new-env old-env)
  1855.     (let* ((name (cadr form))
  1856.        (arglist (caddr form))
  1857.            (body (cdddr form))
  1858.            (walked-arglist (walk-arglist arglist context new-env))
  1859.            (walked-body
  1860.              (walk-declarations body #'walk-repeat-eval new-env)))
  1861.       (relist* form
  1862.                (car form)
  1863.            name
  1864.            walked-arglist
  1865.                walked-body))))  
  1866.  
  1867. (defun walk-setq (form context env)
  1868.   (if (cdddr form)
  1869.       (let* ((expanded
  1870.                (let ((collect NIL)
  1871.                      (ptr (cdr form)))
  1872.                  (loop (push `(setq ,(car ptr) ,(cadr ptr)) collect)
  1873.                        (setf ptr (cddr ptr))
  1874.                        (unless ptr
  1875.                          (return (nreverse collect))))))
  1876.          (walked (walk-repeat-eval expanded env)))
  1877.     (if (eq expanded walked)
  1878.         form
  1879.         `(progn ,@walked)))
  1880.       (let* ((var (cadr form))
  1881.          (val (caddr form))
  1882.          (symmac (car (variable-symbol-macro-p var env))))
  1883.     (if symmac
  1884.         (let* ((expanded `(setf ,(cddr symmac) ,val))
  1885.            (walked (walk-form-internal expanded context env)))
  1886.           (if (eq expanded walked)
  1887.           form
  1888.           walked))
  1889.         (relist form 'setq
  1890.             (walk-form-internal var :set env)
  1891.             (walk-form-internal val :eval env))))))
  1892.  
  1893. (defun walk-symbol-macrolet (form context old-env)
  1894.   (declare (ignore context))
  1895.   (let* ((bindings (cadr form)))
  1896.     (walker-environment-bind
  1897.     (new-env old-env
  1898.          :lexical-variables
  1899.          (append (mapcar #'(lambda (binding)
  1900.                      `(,(car binding)
  1901.                        :macro . ,(cadr binding)))
  1902.                  bindings)
  1903.              (env-lexical-variables old-env)))
  1904.       (relist* form 'symbol-macrolet bindings
  1905.            (walk-repeat-eval (cddr form) new-env)))))
  1906.  
  1907. (defun walk-tagbody (form context env)
  1908.   (recons form (car form) (walk-tagbody-1 (cdr form) context env)))
  1909.  
  1910. (defun walk-tagbody-1 (form context env)
  1911.   (and form
  1912.        (recons form
  1913.                (walk-form-internal (car form)
  1914.                    (if (symbolp (car form)) 'quote context)
  1915.                    env)
  1916.                (walk-tagbody-1 (cdr form) context env))))
  1917.  
  1918. (defun walk-compiler-let (form context old-env)
  1919.   (declare (ignore context))
  1920.   (let ((vars ())
  1921.     (vals ()))
  1922.     (dolist (binding (cadr form))
  1923.       (cond ((symbolp binding) (push binding vars) (push nil vals))
  1924.         (t
  1925.          (push (car binding) vars)
  1926.          (push (eval (cadr binding)) vals))))
  1927.     (relist* form
  1928.          (car form)
  1929.          (cadr form)
  1930.          (progv vars vals (walk-repeat-eval (cddr form) old-env)))))
  1931.  
  1932. (defun walk-macrolet (form context old-env)
  1933.   (walker-environment-bind (macro-env
  1934.                 nil
  1935.                 :walk-function (env-walk-function old-env))
  1936.     (labels ((walk-definitions (definitions)
  1937.            (and definitions
  1938.             (let ((definition (car definitions)))
  1939.               (recons definitions
  1940.                               (relist* definition
  1941.                                        (car definition)
  1942.                                        (walk-arglist (cadr definition)
  1943.                              context
  1944.                              macro-env
  1945.                              t)
  1946.                                        (walk-declarations (cddr definition)
  1947.                               #'walk-repeat-eval
  1948.                               macro-env))
  1949.                   (walk-definitions (cdr definitions)))))))
  1950.       (with-new-definition-in-environment (new-env old-env form)
  1951.     (relist* form
  1952.          (car form)
  1953.          (walk-definitions (cadr form))
  1954.          (walk-declarations (cddr form)
  1955.                     #'walk-repeat-eval
  1956.                     new-env))))))
  1957.  
  1958. (defun walk-flet (form context old-env)
  1959.   (labels ((walk-definitions (definitions)
  1960.          (if (null definitions)
  1961.          ()
  1962.          (recons definitions
  1963.              (walk-lambda (car definitions) context old-env)
  1964.              (walk-definitions (cdr definitions))))))
  1965.     (recons form
  1966.         (car form)
  1967.         (recons (cdr form)
  1968.             (walk-definitions (cadr form))
  1969.             (with-new-definition-in-environment (new-env old-env form)
  1970.               (walk-declarations (cddr form)
  1971.                      #'walk-repeat-eval
  1972.                      new-env))))))
  1973.  
  1974. (defun walk-labels (form context old-env)
  1975.   (with-new-definition-in-environment (new-env old-env form)
  1976.     (labels ((walk-definitions (definitions)
  1977.            (if (null definitions)
  1978.            ()
  1979.            (recons definitions
  1980.                (walk-lambda (car definitions) context new-env)
  1981.                (walk-definitions (cdr definitions))))))
  1982.       (recons form
  1983.           (car form)
  1984.           (recons (cdr form)
  1985.               (walk-definitions (cadr form))
  1986.               (walk-declarations (cddr form)
  1987.                      #'walk-repeat-eval
  1988.                      new-env))))))
  1989.  
  1990. (defun walk-if (form context env)
  1991.   (let ((predicate (cadr form))
  1992.     (arm1 (caddr form))
  1993.     (arm2 
  1994.       (if (cddddr form)
  1995.           (progn
  1996.         (warn "In the form:~%~S~%~
  1997.                        IF only accepts three arguments, you are using ~D.~%~
  1998.                        It is true that some Common Lisps support this, but ~
  1999.                        it is not~%~
  2000.                        truly legal Common Lisp.  For now, this code ~
  2001.                        walker is interpreting ~%~
  2002.                        the extra arguments as extra else clauses. ~
  2003.                        Even if this is what~%~
  2004.                        you intended, you should fix your source code."
  2005.               form
  2006.               (length (the list (cdr form))))
  2007.         (cons 'progn (cdddr form)))
  2008.           (cadddr form))))
  2009.     (relist form
  2010.         'if
  2011.         (walk-form-internal predicate context env)
  2012.         (walk-form-internal arm1 context env)
  2013.         (walk-form-internal arm2 context env))))
  2014.  
  2015.  
  2016. ;;;
  2017. ;;; Tests tests tests
  2018. ;;;
  2019.  
  2020. #|
  2021. ;;; 
  2022. ;;; Here are some examples of the kinds of things you should be able to do
  2023. ;;; with your implementation of the macroexpansion environment hacking
  2024. ;;; mechanism.
  2025. ;;; 
  2026. ;;; with-lexical-macros is kind of like macrolet, but it only takes names
  2027. ;;; of the macros and actual macroexpansion functions to use to macroexpand
  2028. ;;; them.  The win about that is that for macros which want to wrap several
  2029. ;;; macrolets around their body, they can do this but have the macroexpansion
  2030. ;;; functions be compiled.  See the WITH-RPUSH example.
  2031. ;;;
  2032. ;;; If the implementation had a special way of communicating the augmented
  2033. ;;; environment back to the evaluator that would be totally great.  It would
  2034. ;;; mean that we could just augment the environment then pass control back
  2035. ;;; to the implementations own compiler or interpreter.  We wouldn't have
  2036. ;;; to call the actual walker.  That would make this much faster.  Since the
  2037. ;;; principal client of this is defmethod it would make compiling defmethods
  2038. ;;; faster and that would certainly be a win.
  2039. ;;;
  2040. (defmacro with-lexical-macros (macros &body body &environment old-env)
  2041.   (with-augmented-environment (new-env old-env :macros macros)
  2042.     (walk-form (cons 'progn body) :environment new-env)))
  2043.  
  2044. (defun expand-rpush (form env)
  2045.   `(push ,(caddr form) ,(cadr form)))
  2046.  
  2047. (defmacro with-rpush (&body body)
  2048.   `(with-lexical-macros ,(list (list 'rpush #'expand-rpush)) ,@body))
  2049.  
  2050.  
  2051. ;;;
  2052. ;;; Unfortunately, I don't have an automatic tester for the walker.  
  2053. ;;; Instead there is this set of test cases with a description of
  2054. ;;; how each one should go.
  2055. ;;; 
  2056. (defmacro take-it-out-for-a-test-walk (form)
  2057.   `(take-it-out-for-a-test-walk-1 ',form))
  2058.  
  2059. (defun take-it-out-for-a-test-walk-1 (form)
  2060.   (terpri)
  2061.   (terpri)
  2062.   (let ((copy-of-form (copy-tree form))
  2063.     (result (walk-form form nil
  2064.           #'(lambda (x y env)
  2065.               (format t "~&Form: ~S ~3T Context: ~A" x y)
  2066.               (when (symbolp x)
  2067.             (let ((lexical (variable-lexical-p x env))
  2068.                   (special (variable-special-p x env)))
  2069.               (when lexical
  2070.                 (format t ";~3T")
  2071.                 (format t "lexically bound"))
  2072.               (when special
  2073.                 (format t ";~3T")
  2074.                 (format t "declared special"))
  2075.               (when (boundp x)
  2076.                 (format t ";~3T")
  2077.                 (format t "bound: ~S " (eval x)))))
  2078.               x))))
  2079.     (cond ((not (equal result copy-of-form))
  2080.        (format t "~%Warning: Result not EQUAL to copy of start."))
  2081.       ((not (eq result form))
  2082.        (format t "~%Warning: Result not EQ to copy of start.")))
  2083.     (pprint result)
  2084.     result))
  2085.  
  2086. (defmacro foo (&rest ignore) ''global-foo)
  2087.  
  2088. (defmacro bar (&rest ignore) ''global-bar)
  2089.  
  2090. (take-it-out-for-a-test-walk (list arg1 arg2 arg3))
  2091. (take-it-out-for-a-test-walk (list (cons 1 2) (list 3 4 5)))
  2092.  
  2093. (take-it-out-for-a-test-walk (progn (foo) (bar 1)))
  2094.  
  2095. (take-it-out-for-a-test-walk (block block-name a b c))
  2096. (take-it-out-for-a-test-walk (block block-name (list a) b c))
  2097.  
  2098. (take-it-out-for-a-test-walk (catch catch-tag (list a) b c))
  2099. ;;;
  2100. ;;; This is a fairly simple macrolet case.  While walking the body of the
  2101. ;;; macro, x should be lexically bound. In the body of the macrolet form
  2102. ;;; itself, x should not be bound.
  2103. ;;; 
  2104. (take-it-out-for-a-test-walk
  2105.   (macrolet ((foo (x) (list x) ''inner))
  2106.     x
  2107.     (foo 1)))
  2108.  
  2109. ;;;
  2110. ;;; A slightly more complex macrolet case.  In the body of the macro x
  2111. ;;; should not be lexically bound.  In the body of the macrolet form itself
  2112. ;;; x should be bound.  Note that THIS CASE WILL CAUSE AN ERROR when it
  2113. ;;; tries to macroexpand the call to foo.
  2114. ;;; 
  2115. (take-it-out-for-a-test-walk
  2116.      (let ((x 1))
  2117.        (macrolet ((foo () (list x) ''inner))
  2118.      x
  2119.      (foo))))
  2120.  
  2121. ;;;
  2122. ;;; A truly hairy use of compiler-let and macrolet.  In the body of the
  2123. ;;; macro x should not be lexically bound.  In the body of the macrolet
  2124. ;;; itself x should not be lexically bound.  But the macro should expand
  2125. ;;; into 1.
  2126. ;;; 
  2127. (take-it-out-for-a-test-walk
  2128.   (compiler-let ((x 1))
  2129.     (let ((x 2))
  2130.       (macrolet ((foo () x))
  2131.     x
  2132.     (foo)))))
  2133.  
  2134.  
  2135. (take-it-out-for-a-test-walk
  2136.   (flet ((foo (x) (list x y))
  2137.      (bar (x) (list x y)))
  2138.     (foo 1)))
  2139.  
  2140. (take-it-out-for-a-test-walk
  2141.   (let ((y 2))
  2142.     (flet ((foo (x) (list x y))
  2143.        (bar (x) (list x y)))
  2144.       (foo 1))))
  2145.  
  2146. (take-it-out-for-a-test-walk
  2147.   (labels ((foo (x) (bar x))
  2148.        (bar (x) (foo x)))
  2149.     (foo 1)))
  2150.  
  2151. (take-it-out-for-a-test-walk
  2152.   (flet ((foo (x) (foo x)))
  2153.     (foo 1)))
  2154.  
  2155. (take-it-out-for-a-test-walk
  2156.   (flet ((foo (x) (foo x)))
  2157.     (flet ((bar (x) (foo x)))
  2158.       (bar 1))))
  2159.  
  2160. (take-it-out-for-a-test-walk (compiler-let ((a 1) (b 2)) (foo a) b))
  2161. (take-it-out-for-a-test-walk (prog () (declare (special a b))))
  2162. (take-it-out-for-a-test-walk (let (a b c)
  2163.                                (declare (special a b))
  2164.                                (foo a) b c))
  2165. (take-it-out-for-a-test-walk (let (a b c)
  2166.                                (declare (special a) (special b))
  2167.                                (foo a) b c))
  2168. (take-it-out-for-a-test-walk (let (a b c)
  2169.                                (declare (special a))
  2170.                                (declare (special b))
  2171.                                (foo a) b c))
  2172. (take-it-out-for-a-test-walk (let (a b c)
  2173.                                (declare (special a))
  2174.                                (declare (special b))
  2175.                                (let ((a 1))
  2176.                                  (foo a) b c)))
  2177. (take-it-out-for-a-test-walk (eval-when ()
  2178.                                a
  2179.                                (foo a)))
  2180. (take-it-out-for-a-test-walk (eval-when (eval when load)
  2181.                                a
  2182.                                (foo a)))
  2183.  
  2184. (take-it-out-for-a-test-walk (multiple-value-bind (a b) (foo a b) (list a b)))
  2185. (take-it-out-for-a-test-walk (multiple-value-bind (a b)
  2186.                  (foo a b)
  2187.                    (declare (special a))
  2188.                    (list a b)))
  2189. (take-it-out-for-a-test-walk (progn (function foo)))
  2190. (take-it-out-for-a-test-walk (progn a b (go a)))
  2191. (take-it-out-for-a-test-walk (if a b c))
  2192. (take-it-out-for-a-test-walk (if a b))
  2193. (take-it-out-for-a-test-walk ((lambda (a b) (list a b)) 1 2))
  2194. (take-it-out-for-a-test-walk ((lambda (a b) (declare (special a)) (list a b))
  2195.                   1 2))
  2196. (take-it-out-for-a-test-walk (let ((a a) (b a) (c b)) (list a b c)))
  2197. (take-it-out-for-a-test-walk (let* ((a a) (b a) (c b)) (list a b c)))
  2198. (take-it-out-for-a-test-walk (let ((a a) (b a) (c b))
  2199.                                (declare (special a b))
  2200.                                (list a b c)))
  2201. (take-it-out-for-a-test-walk (let* ((a a) (b a) (c b))
  2202.                                (declare (special a b))
  2203.                                (list a b c)))
  2204. (take-it-out-for-a-test-walk (let ((a 1) (b 2))
  2205.                                (foo bar)
  2206.                                (declare (special a))
  2207.                                (foo a b)))
  2208. (take-it-out-for-a-test-walk (multiple-value-call #'foo a b c))
  2209. (take-it-out-for-a-test-walk (multiple-value-prog1 a b c))
  2210. (take-it-out-for-a-test-walk (progn a b c))
  2211. (take-it-out-for-a-test-walk (progv vars vals a b c))
  2212. (take-it-out-for-a-test-walk (quote a))
  2213. (take-it-out-for-a-test-walk (return-from block-name a b c))
  2214. (take-it-out-for-a-test-walk (setq a 1))
  2215. (take-it-out-for-a-test-walk (setq a (foo 1) b (bar 2) c 3))
  2216. (take-it-out-for-a-test-walk (tagbody a b c (go a)))
  2217. (take-it-out-for-a-test-walk (the foo (foo-form a b c)))
  2218. (take-it-out-for-a-test-walk (throw tag-form a))
  2219. (take-it-out-for-a-test-walk (unwind-protect (foo a b) d e f))
  2220.  
  2221. (defmacro flet-1 (a b) ''outer)
  2222. (defmacro labels-1 (a b) ''outer)
  2223.  
  2224. (take-it-out-for-a-test-walk
  2225.   (flet ((flet-1 (a b) () (flet-1 a b) (list a b)))
  2226.     (flet-1 1 2)
  2227.     (foo 1 2)))
  2228. (take-it-out-for-a-test-walk
  2229.   (labels ((label-1 (a b) () (label-1 a b)(list a b)))
  2230.     (label-1 1 2)
  2231.     (foo 1 2)))
  2232. (take-it-out-for-a-test-walk (macrolet ((macrolet-1 (a b) (list a b)))
  2233.                                (macrolet-1 a b)
  2234.                                (foo 1 2)))
  2235.  
  2236. (take-it-out-for-a-test-walk (macrolet ((foo (a) `(inner-foo-expanded ,a)))
  2237.                                (foo 1)))
  2238.  
  2239. (take-it-out-for-a-test-walk (progn (bar 1)
  2240.                                     (macrolet ((bar (a)
  2241.                          `(inner-bar-expanded ,a)))
  2242.                                       (bar 2))))
  2243.  
  2244. (take-it-out-for-a-test-walk (progn (bar 1)
  2245.                                     (macrolet ((bar (s)
  2246.                          (bar s)
  2247.                          `(inner-bar-expanded ,s)))
  2248.                                       (bar 2))))
  2249.  
  2250. (take-it-out-for-a-test-walk (cond (a b)
  2251.                                    ((foo bar) a (foo a))))
  2252.  
  2253.  
  2254. (let ((the-lexical-variables ()))
  2255.   (walk-form '(let ((a 1) (b 2))
  2256.         #'(lambda (x) (list a b x y)))
  2257.          ()
  2258.          #'(lambda (form context env)
  2259.          (when (and (symbolp form)
  2260.                 (variable-lexical-p form env))
  2261.            (push form the-lexical-variables))
  2262.          form))
  2263.   (or (and (= (length the-lexical-variables) 3)
  2264.        (member 'a the-lexical-variables)
  2265.        (member 'b the-lexical-variables)
  2266.        (member 'x the-lexical-variables))
  2267.       (error "Walker didn't do lexical variables of a closure properly.")))
  2268.     
  2269. |#
  2270.  
  2271. ()
  2272.  
  2273.